""" plugin inteface for XBMC player 

Example:

import sys
from xbmcPluginInterface import XBMCPluginInterface
from myPlugin import MyPlugin

iface = XBMCPluginInterface()
p = MyPlugin( iface )
p.call( *sys.argv )

"""

__author__ = "Tomas Pokorny (tomas.zemres@gmail.com)"
__version__ = "0.3"
__license__ = "GPL"

__all__ = ["XBMCPluginInterface"]

import sys
import urllib
import xbmc
import xbmcgui
import xbmcplugin

try:
    # new XBMC 10.05 addons:
    import xbmcaddon
except ImportError:
    # old XBMC
    class xbmcaddon:
        """ fake xbmcaddon module """
        __version__ = "(old XBMC)"
        class Addon:
            """ fake xbmcaddon.Addon class """
            def __init__(self, id):
                self.id = id

            def getSetting(self, key):
                return xbmcplugin.getSetting(key)

            def setSetting(self, key, value):
                xbmcplugin.setSetting(key, value)

            def getLocalizedString(self, id):
                return xbmc.getLocalizedString(id)

            def getAddonInfo(self, id):
                if (id == 'id'):
                    return self.id
                return None



class XBMCPluginInterface:
    """ XBMC plugin interface class for plugins based on BasePlugin """
    progress = None
    addon = None


    def __init__(self, addon_id=None):
        """ Constructor """
        # addon init
        self.addon = xbmcaddon.Addon(addon_id)

        # Log plugin identification
        addon_version = self.addon.getAddonInfo('version')
        info_msg = "[plugin initialization]" \
                    + " addon.id=" + repr( self.addon.getAddonInfo('id') ) \
                    + " addon.name=" + repr( self.addon.getAddonInfo('name') ) \
                    + " addon.version=" + repr( self.addon.getAddonInfo('version') ) \
                    + " sys.version=" + repr(sys.version) \
                    + " sys.platform=" + repr(sys.platform)
        xbmc.log(info_msg, xbmc.LOGNOTICE)


    def getCallParams(self, baseurl, handle, query=''):
        self.baseurl = baseurl
        self.handle  = int(handle)
        self.totalItems = 0
        self.updateListing = False
        self.cacheToDisc = True

        params = self.parseQuery(query)
        callName = params.pop('call', None)
        xbmc.log( "Plugin call %r; params: %r" % (callName, params), xbmc.LOGNOTICE )
        return (callName, params)


    def parseQuery(self, query):
        """ Parse argumets from query like '?param=value&param2=value2'
            and return it as dictionary
        """
        params = {}
        if query:
            query = query.split('?')[-1]
            for part in query.split('&'):
                (key, value) = part.split('=')
                params[key] = urllib.unquote_plus(value)
        return params


    def generateURL(self, _item=None, **params):
        if _item:
            if _item.path and not _item.call:
                return _item.path
            params['call'] = _item.call
            params.update( _item.param )
        return self.baseurl + '?' + urllib.urlencode(params)


    def mkListItem(self, item):
        """ Generate xbmcgui.ListItem from PItem """
        params = {}
        if item.iconURL:
            params['thumbnailImage'] = item.iconURL
        listItem = xbmcgui.ListItem(item.label, **params)
        if item.info:
            listItem.setInfo(type=item.type, infoLabels=item.info)
        if item.menuItems:
            listItem.addContextMenuItems( item.menuItems )
        return listItem


    def setSorting(self, key):
        constantName = 'SORT_METHOD_'+(key or 'NONE')
        if not hasattr(xbmcplugin, constantName):
            raise Exception('Invalid sort method: '+repr(key))

        sortID = getattr(xbmcplugin, constantName)
        xbmcplugin.addSortMethod(self.handle, sortID)


    def addItem(self, item):
        """ Add item to directory """
        url = self.generateURL(item)
        listItem = self.mkListItem(item)

        params = [self.handle, url, listItem, bool(item.isFolder)]
        if self.totalItems:
            params.append(int(self.totalItems))
        xbmcplugin.addDirectoryItem(*params)


    def endOfList(self):
        xbmcplugin.endOfDirectory( self.handle, True,
                        bool(self.updateListing), bool(self.cacheToDisc) )


    def cancelOperation(self):
        xbmcplugin.endOfDirectory( self.handle, False)


    def getSetting(self, key):
        return self.addon.getSetting(key)
        

    def setSetting(self, key, value):
        self.addon.setSetting(key, value)
        

    def play(self, url, item=None, subtitles=None):
        params = [url]
        if item:
            params.append( self.mkListItem )
        player = xbmc.Player()
        player.play(*params)
        if subtitles:
            player.setSubtitles(subtitles)
        

    def log(self, message, level):
        constantName = 'LOG'+level
        if not hasattr(xbmc, constantName):
            raise Exception('Invalid log level: '+repr(level))
        xbmc.log(message, getattr(xbmc, constantName))


    def getLocalizedString(self, id):
        return self.addon.getLocalizedString(id)


    def translatePath(self, url):
        return xbmc.translatePath(url)


    def execute(self, command):
        xbmc.executebuiltin(command)


    def okDialog(self, heading, line1, line2='', line3=''):
        dialog = xbmcgui.Dialog()
        return dialog.ok(heading, line1, line2, line3)


    def textDialog(self, heading='', default='', hidden=False):
        dialog = xbmc.Keyboard(default, heading, hidden)
        dialog.doModal()
        if dialog.isConfirmed():
            return dialog.getText()
        return None


    # Progress dialog methods #

    def newProgress(self, heading, line1, *otherLines):
        if not self.progress:
            self.progress = xbmcgui.DialogProgress()
        self.progress.create(heading)
        self.progress.update( 0, line1, *otherLines )


    def updateProgress(self, percent, *lines):
        if self.progress.iscanceled():
            raise CancelOperation("Cancel has pressed on progress dialog")
        self.progress.update( int(percent), *lines )


    def closeProgress(self):
        if self.progress.iscanceled():
            raise CancelOperation("Cancel has pressed on progress dialog")
        self.progress.close()


